$(
	function () {
		(function ($R) {
	
/* more css, outside frame */
/* ======================= */
	
	var 
		_document = $R.win.document,
		_html = _document.getElementsByTagName('html')[0],
		_html_identifier = (_html.id && _html.id > '' && _html.id.match(/^[a-z]/i) != null ? '#'+_html.id : 'html'),
		_body = _document.getElementsByTagName('body')[0],
		_body_identifier = (_body.id && _body.id > '' && _body.id.match(/^[a-z]/i) != null ? '#'+_body.id : 'body'),
		_cssText = ''
		
		+	_html_identifier + '.readableVisible, '
		+	'html > ' + _body_identifier + '.readableVisible, '
		+	_body_identifier + '.readableVisible '
		+	'{ '
		+		'margin: 0 !important; padding: 0 !important; border: 0 !important; '
		+		'overflow: hidden !important; overflow-x: hidden !important; overflow-y: hidden !important; '
		+		'position: static !important; '
		+	'} '

		
		+	_html_identifier + '.readableBeforeVisible, '
		+	'html > ' + _body_identifier + '.readableBeforeVisible, '
		+	_body_identifier + '.readableBeforeVisible '
		+	'{ '
		+		'position: static !important; '
		+	'} '

		
		+	_html_identifier + '.readableVisible object, '
		+	_html_identifier + '.readableVisible embed, '
		+	_html_identifier + '.readableVisible iframe, '

		+	'html > ' + _body_identifier + '.readableVisible object, '
		+	'html > ' + _body_identifier + '.readableVisible embed, '
		+	'html > ' + _body_identifier + '.readableVisible iframe, '

		+	_body_identifier + '.readableVisible object, '
		+	_body_identifier + '.readableVisible embed, '
		+	_body_identifier + '.readableVisible iframe '
		+ 	'{ '
		+		'display: none !important; '
		+	'} '
	;

	var _cssElement = _document.createElement('style');
		_cssElement.setAttribute('id', 'readableCSS2');
		_cssElement.setAttribute('type', 'text/css');
		
	if (_cssElement.styleSheet) {_cssElement.styleSheet.cssText = _cssText; }
		else { _cssElement.appendChild(_document.createTextNode(_cssText)); }

	var _coverElement = document.createElement('div');
		_coverElement.setAttribute('id', 'readable_app_cover');
		_coverElement.setAttribute('style', 'display: none');
		
	_body.appendChild(_cssElement);
	_body.appendChild(_coverElement);

	
/* cache vars */
/* ========== */

	$R.$iframeDocument = $(document);
	$R.$document = $(_document);
	$R.$iframe = $R.$document.find('#readable_app_iframe');
	$R.$cover = $R.$document.find('#readable_app_cover');
	
	
/* check for rtl */
/* ============= */

	$R.rtl = false;
	if ($R.$document.find("div[dir='rtl'], table[dir='rtl'], td[dir='rtl']").length > 0)
		{ $('html').addClass('couldBeRTL'); }
	
	$R.makeRTL = function ()
	{
		$R.rtl = true;
		$('html')
			.attr('dir', 'rtl')
			.addClass('couldBeRTL')
			.addClass('rtl');
	};
	
	$R.makeNotRTL = function ()
	{
		$R.rtl = false;
		$('html')
			.attr('dir', '')
			.removeClass('rtl');
	};
	
	$R.$document
		.find('html, body')
			.each(function (_i, _e)
			{
				switch (true) {
					case ($(_e).attr('dir') == 'rtl'):
					case ($(_e).css('direction') == 'rtl'):

					case ($(_e).attr('lang') == 'he'):
					case ($(_e).attr('lang') == 'he-il'):
					case ($(_e).attr('lang') == 'ar'):
					case ($(_e).attr('lang') == 'ur'):

						$R.makeRTL();
						return false;
				}
			});

			
/* more html, inside frame */
/* ======================= */
	
	$('#body').html(''
		+	'<div id="box">'
		+		'<div id="box_inner">'
		+			'<div id="embedded_logo">'
		+				($R.embedded && $R.embeddedOptions['logo'] > '' ?
						'<img src="'+$R.embeddedOptions['logo']+'" alt=""/>' :
						'<a href="#">'+$R.win.location.host+'</a>')
		+			'</div>'
		+			'<div id="rtl_box"><strong>Right to left?</strong><a href="#" id="rtl_box_on">Yes.</a><a id="rtl_box_off" href="#">No.</a></div>'
		+			'<div id="text"></div>'
		+			'<div id="menu">'
		+				'<a id="menu_close" href="#" title="You can also double-click the background, or single-click the left edge of the screen.">Close</a>'
		+				'<a id="menu_print" href="#" title="Only prints the text in Readable\'s overlay.">Print</a>'
		+				'<a id="menu_settings" target="_blank" title="Takes you to Readable\'s setup page, where you can alter your current style.">Change Style</a>'
		+				'<a id="menu_problem" target="_blank" title="Encountered a problem? Tell me about it.">Report Bug</a>'
		+			'</div>'
		+			'<div id="my_news"><strong>News:</strong><br/>Readable just got a major update to its text extraction algorithm.<br/>Please <a target="_blank" href="http://readable.tastefulwords.com/problem/">let me know</a>, if you encounter any problems.</div>'
		+			'<div id="embedded_powered_by">Powered by <a target="_blank" href="http://readable.tastefulwords.com/?get"><strong>Readable</strong></a>.<br/>'+'Get <a target="_blank" href="http://readable.tastefulwords.com/?get">this view</a> on any website.</div>'
		+		'</div>'
		+	'</div>'
		+	'<div id="background"></div>'
		+	'<a id="fitts" href="#" title="Click to close Readable."></a>'
		+	'<div id="floating">'
		+		'<a href="#" id="floating_scroll_back" title="Just Clicked on an internal link? Scroll back to where you were."><strong>&larr;</strong> scroll back</a>'
		+		'<a href="#" id="floating_close" title="You can also double-click the background, single-click the left edge of the screen, or use the Close menu item.">close</a>'
		+		'<a href="#" id="floating_menu" title="Go to Readable\'s Menu, at the bottom of the overlay.">&darr;</a>'
		+	'</div>'
		+	'<div id="menu_debug_time"></div>'
	);

	
/* cache vars */
/* ========== */

	$R.$iframeText = $('#text');
	
	$R.visible = false;
	$R.URL = ''
		+ $R.win.location.protocol + '//'
		+ $R.win.location.host
		+ $R.win.location.pathname
	;
	
/* setup ux */
/* ======== */

	$('#fitts').click(function(){ $R.hide(); return false; });
	$('#background').dblclick(function(){ $R.hide(); return false; });
	$('#embedded_logo').find('a, img').click(function(){ $R.hide(); return false; });

	$('#floating_menu').click(function(){ $(window).scrollTop($R.$iframeText.height()); return false; });
	$('#floating_close').click(function(){ $R.hide(); return false; });
	$('#floating_scroll_back').click(function(){ $(window).scrollTop($R.scrollPosition); $R.scrollPosition=0; $('#bottom_scroll_back').hide(); return false; });
	
	$('#menu_close').click(function(){ $R.hide(); return false; });
	$('#menu_print').click(function(){ window.print(); return false; });
	$('#menu_problem').attr('href', $R.linksPath+'problem/');
	
	$('#rtl_box_on').click(function(){ $R.makeRTL(); return false; });
	$('#rtl_box_off').click(function(){ $R.makeNotRTL(); return false; });
	
	//	scroll-back
	$R.scrollPosition = 0;
	$R.goToNamedAnchor = function (_anchor)
	{
		var _$e = $("[id='"+_anchor+"'], [name='"+_anchor+"']");
		if (_$e.length > 0); else { return; }
		
		$R.scrollPosition = $(window).scrollTop();
		$('#bottom_scroll_back').show();
		
		$(window).scrollTop(_$e.offset().top);
	};

	
/* options */
/* ======= */

	
	$R.setOptions = function ()
	{
		var 
			_resetOptions = false, 
			_resetBase = false,
			_applyOptions = {}
		;

		//	if null, set default
		if ($R.options); else {	$R.options = $R._defaultOptions; }
		
		//	create applyOptions
		for (var _option in $R._defaultOptions)
		{
			switch (true)
			{
				case (!(_option in $R.options)):
				case ($R.options[_option].match(/[<>]/gi)):
					_applyOptions[_option] = $R._defaultOptions[_option];
					break;
					
				default:
					_applyOptions[_option] = $R.options[_option].replace(/quote\(([^\)]*?)\)/gi, '"$1"');
					break;
			}
		}
			
		if ($R.currentOptions)
		{
			_resetOptions = false;
			for (var _option in _applyOptions) {
				if (_applyOptions[_option] != $R.currentOptions[_option]) {
					_resetOptions = true; break;
				}
			}
			
			_resetBase = (_applyOptions['base'] != $R.currentOptions['base']);
		}
		else
		{
			_resetOptions = true;
			_resetBase = true;
		}
		
		if (_resetBase)
		{
			//	remove
			$('#baseCSS').remove();
			
			//	append
			$('head').append('<link id="baseCSS" rel="stylesheet" href="'+$R.path+'base-'+_applyOptions['base']+'-'+$R.compileTime+'.css'+'" type="text/css" />');
		}
		
		if (_resetOptions)
		{
			//	remove
			$('#optionsCSS').remove();
			
			//	google fonts
			var 
				_check_google_font = function (_match, _font)
				{
					if (_font in $R.googleFontsIndex); else { return; }
					
					var _font_key = _font.replace(/\s/gi, '+');
					$('head').append('<link href="http://fonts.googleapis.com/css?family='+_font_key+'" rel="stylesheet" type="text/css" />');
				},
				_double_check_font = function (fontVariable)
				{
					_applyOptions[fontVariable].replace(/"([^",]+)"/gi, _check_google_font);
					_applyOptions[fontVariable].replace(/([^",\s]+)/gi, _check_google_font);				
				}
			;

			//	check fonts
			_double_check_font('text_font');
			_double_check_font('text_font_header');
			_double_check_font('text_font_monospace');
			
			_applyOptions['custom_css'].replace(/font-family: "([^",]+)"/gi, _check_google_font);
			_applyOptions['custom_css'].replace(/font-family: ([^",\s]+)/gi, _check_google_font);
			
			//	custom css
			//	use options in the custom_css
			_applyOptions['custom_css'] = _applyOptions['custom_css'].replace(/\[=custom_css\]/gi, '');
			_applyOptions['custom_css'] = _applyOptions['custom_css'].replace(
				/\[=([a-z_]+?)\]/gi,
				function (_match, _key) { return _applyOptions[_key]; }
			);
			
			//	create css
			var _cssText = (''
				+	'#body { '
				+		'font-family: [=text_font]; '
				+		'font-size: [=text_size]; '
				+		'line-height: [=text_line_height]; '
				+		'color: [=color_text]; '
				+		'text-align: '+(_applyOptions['text_align'] == 'justified' ? 'justify' : 'left')+'; '
				+	'} '
				
				+	'#background { background-color: [=color_background]; } '
				+	'#box { width: [=box_width]; background-color: [=color_background]; } '
				
				+	'a { color: [=color_links]; } '
				+	'a:visited { color: [=color_text]; } '

				+	'img { border-color: [=color_text]; } '
				+	'a img { border-color: [=color_links]; } '
				+	'a:visited img { border-color: [=color_text]; } '

				+	'h1 a, h2 a { color: [=color_text]; } '
				+	'h1, h2, h3, h4, h5, h6 { '
				+		(_applyOptions['text_font_header'] == '' ? '' : 
						'font-family: [=text_font_header]; ')
				+	'} '

				+	'pre { background-color: [=color_background]; } '
				+	'pre, code { font-family: [=text_font_monospace]; } '
				+	'hr { border-color: [=color_text]; } '

				
				+	'#floating a { background-color: [=color_text]; color: [=color_background]; } '
				+	'#floating #floating_menu { background-color: transparent; color: [=color_text]; } '
				+	'#fitts:hover { background-color: [=color_text]; } '

				+	'#menu, #rtl_box { background-color: [=color_text]; color: [=color_background]; } '
				+	'#menu a, #rtl_box a { color: [=color_background]; border-color: [=color_background]; } '

				
				+	'[=custom_css] '
				
				+	'html.rtl #body { text-align: ' + (_applyOptions['text_align'] == 'justified' ? 'justify' : 'right')+' !important; } '
				+	'h1, h2, h3, h4, h5, h6 { text-align: left; } '
				+	'html.rtl h1, html.rtl h2, html.rtl h3, html.rtl h4, html.rtl h5, html.rtl h6 { text-align: right !important; } '
				
			).replace(
				/\[=([a-z_]+?)\]/gi,
				function (_match, _key) { return _applyOptions[_key]; }
			);
		
			//	append
			var _cssElement = document.createElement('style');
				_cssElement.setAttribute('type', 'text/css');
				_cssElement.setAttribute('id', 'optionsCSS');
				
			if (_cssElement.styleSheet) { _cssElement.styleSheet.cssText = _cssText; }
				else { _cssElement.appendChild(document.createTextNode(_cssText)); }
		
			$('head').append(_cssElement);
			
			//	cover background-color
			$R.$cover.css('background-color', _applyOptions['color_background']);
		}
		
		//	current options, not modified
		$R.currentOptions = $R.options;

		//	change settings
		var changeSettingsURL = ''
			+	$R.linksPath + '?'
			+	'setup'
			+	'&change'
		;
	
		for (var __opt in $R.currentOptions) {
			changeSettingsURL += 
				'&' + __opt + '=' + encodeURIComponent($R.currentOptions[__opt]);
		}
	
		$('#menu_settings').attr('href', changeSettingsURL);
	};

	$R.setRTL = function ()
	{
		//	append
		var _cssElement = document.createElement('style');
			_cssElement.setAttribute('type', 'text/css');
			_cssElement.setAttribute('id', 'rtlCSS');
			
		if (_cssElement.styleSheet) { _cssElement.styleSheet.cssText = _cssText; }
			else { _cssElement.appendChild(document.createTextNode(_cssText)); }
	
		$('head').append(_cssElement);
	};
	
	
	$R._defaultOptions = {
		'text_font': 			'"Palatino Linotype", Palatino, "Book Antigua", Georgia, serif',
		'text_font_monospace':	'"Courier New", Courier, monospace',
		'text_font_header':		'',

		'text_size': 			'18px',
		'text_line_height': 	'1.5',
		'box_width': 			'30em',

		'color_background': 	'#F5F5F5',
		'color_text': 			'#000000',
		'color_links': 			'#0000FF',
		
		'text_align': 			'normal',
		'base': 				'blueprint',
		'custom_css':			''
	};

	
	$R.googleFontsIndex = {};
	$R.googleFontsArray =
	[
		'Arvo',
		'Bentham',
		'Cardo',
		'Copse',
		'Corben',
		'Crimson Text',
		'Droid Serif',
		'Goudy Bookletter 1911',
		'Gruppo',
		'IM Fell',
		'Josefin Slab',
		'Kreon',
		'Meddon',
		'Merriweather',
		'Neuton',
		'OFL Sorts Mill Goudy TT',
		'Old Standard TT',
		'Philosopher',
		'PT Serif',
		'Radley',
		'Tinos',
		'Vollkorn',
		
		'Allerta',
		'Anton',
		'Arimo',
		'Bevan',
		'Buda',
		'Cabin',
		'Cantarell',
		'Coda',
		'Cuprum',
		'Droid Sans',
		'Geo',
		'Josefin Sans',
		'Lato',
		'Lekton',
		'Molengo',
		'Nobile',
		'Orbitron',
		'PT Sans',
		'Puritan',
		'Raleway',
		'Syncopate',
		'Ubuntu',
		'Yanone Kaffeesatz',
		
		'Anonymous Pro',
		'Cousine',
		'Droid Sans Mono',
		'Inconsolata'	
	];

	for (var i=0, ii=$R.googleFontsArray.length; i<ii; i++) {
		$R.googleFontsIndex[$R.googleFontsArray[i]] = 1;
	}
	

/* content */
/* ======= */

	$R.getContent = function (checkIfHomePage)
	{
		switch (true)
		{
			//	text is selected: show that
			case ($R.getContent__manualSelection()):
				return;
				
			//	found the content
			case ($R.getContent__findHere()):
				return;
		}
		
		//	no content found: display body element
		if ($R.debug) { $R.log('display body element'); }
		$R.displayHTML($R.processHTML__getHTMLToProcess([$R.$document.find('body').get(0)]));		
	};
	
	
	$R.getContent__manualSelection = function ()
	{
		var 
			_selection = $R.sel.getSelection($R.win),
			_range = $R.sel.getRange(_selection),
			_html = $R.sel.getRangeHTML(_range),
			_text = $R.sel.getRangeText(_range)
		;
		
		if (_html > '' && _text > ''); else
		{
			_html = null;
			_text = null;
			
			$R.$document.find('frame, iframe').each
			(
				function (_i, _e)
				{
					if (_e.getAttribute('id') == 'readable_app_iframe') { return; }
					
					try
					{
						var
							__doc = $(_e).contents().get(0),
							__win = $R.sel.getWindowFromDocument(__doc),
							__selection = $R.sel.getSelection(__win),
							__range = $R.sel.getRange(__selection),
							__html = $R.sel.getRangeHTML(__range),
							__text = $R.sel.getRangeText(__range)
						;
							
						if (__html > '' && __text > '')
						{
							_html = __html;
							_text = __text;
							
							// stop the each
							return false;
						}
					}
					catch(e) { }
				}
			);
		}
		
		//	haven't found anything		
		if (_html > '' && _text > ''); else { return false; }

		//	probably selected something by mistake
		if ($R.getContent__nrWords(_text) > 50); else { return false; }
		
		//	got some selected text; show it
		$R.displayHTML(_html);
		
		return true;
	};
	
/* functions */	
/* ========= */
	
	$R.sel = {};

	$R.sel.getWindowFromDocument = function (theDocument)
	{
		if (theDocument); else { return null; }
		
		if ('defaultView' in theDocument) {
			arguments.calee = function (theDocument) {
				if (theDocument); else { return null; }
				return theDocument.defaultView;
			};
		}
		else if ('parentWindow' in theDocument) {
			arguments.calee = function (theDocument) {
				if (theDocument); else { return null; }
				return theDocument.parentWindow;
			};
		}
		else {
			arguments.calee = function (theDocument) {
				return null;
			};
		}
		
		return arguments.calee(theDocument);
	};


	$R.sel.getSelection = function (theWindow)
	{
		if (theWindow); else { return null; }
	
		if ('getSelection' in theWindow) {
			arguments.calee = function (theWindow) {
				if (theWindow); else { return null; }
				return theWindow.getSelection();
			};
		}
		else if ('selection' in theWindow.document) {
			arguments.calee = function (theWindow) {
				if (theWindow); else { return null; }
				return theWindow.document.selection;
			};
		}
		else {
			arguments.calee = function (theWindow) {
				return null;
			};
		}
		
		return arguments.calee(theWindow);
	};


	$R.sel.getRange = function (selection)
	{
		if (selection); else { return null; }
	
		if ('getRangeAt' in selection) {
			arguments.calee = function (selection) {
				if (selection); else { return null; }
				if (selection.rangeCount > 0) { return selection.getRangeAt(0); }
				else { return null; }
				//	doesn't work in old versions of safari 
				//	... I don't care
			};
		}
		else if ('createRange' in selection) {
			arguments.calee = function (selection) {
				if (selection); else { return null; }
				return selection.createRange();
			};
		}
		else {
			arguments.calee = function (selection) {
				return null;
			};
		}
		
		return arguments.calee(selection);
	};


	$R.sel.getRangeHTML = function (range)
	{
		if (range); else { return null; }
		
		if ('htmlText' in range) {
			arguments.calee = function (range) {
				if (range); else { return null; }
				return range.htmlText;
			};
		}
		else if ('surroundContents' in range) {
			arguments.calee = function (range) {
				if (range); else { return null; }
				var dummy = range.commonAncestorContainer.ownerDocument.createElement("div");
				dummy.appendChild(range.cloneContents());
				return dummy.innerHTML;
			};
		}
		else {
			arguments.calee = function (range) {
				return null;
			};
		}
		
		return arguments.calee(range);
	};


	$R.sel.getRangeText = function (range)
	{
		if (range); else { return null; }
		
		if ('text' in range) {
			arguments.calee = function (range) {
				if (range); else { return null; }
				return range.text;
			};
		}
		else if ('surroundContents' in range) {
			arguments.calee = function (range) {
				if (range); else { return null; }
				var dummy = range.commonAncestorContainer.ownerDocument.createElement("div");
				dummy.appendChild(range.cloneContents());
				return dummy.textContent;
			};
		}
		else {
			arguments.calee = function (range) {
				return null;
			};
		}
		
		return arguments.calee(range);
	};

	
	$R.getContent__findHere = function ()
	{
		//	get target
		var 
			_target = $R.getContent__findHere__getTargetElement(),
			_has_title = (_target ? _target.getElementsByTagName('h1').length > 0 : false),
			
			_elements = [_target],
			_before = [],
			_after = [],
			
			_prev = _target,
			_prev_test = function (_x)
			{
				if (_x.nodeType); else { return false; }
				if (_x.nodeType == 1); else { return false; }
				
				switch (true)
				{
					case (_x.tagName.match(/^h(1|2|3|4|5|6)$/gi) != null):
					case (_x.tagName.match(/^p|blockquote$/gi) != null):
					case (_x.getElementsByTagName && _x.getElementsByTagName('h1').length > 0):
					case (($.data(_x, 'readableCandidateId') != undefined)):
						return true;
				}
				
				return false;
			}
		;

		//	if not target, return
		if (_target); else { return false; }

		//	rtl (again)
		switch (true)
		{
			case ($(_target).attr('dir') == 'rtl'):
			case ($(_target).css('direction') == 'rtl'):
				$R.makeRTL();
		}
		
		//	check previous siblings
		if (_has_title); else
		{
			while (true)
			{
				//	get
				_prev = _prev.previousSibling;
				if (_prev); else { break; }

				//	test
				if (_prev_test(_prev)); else { continue; }

				//	put
				_elements.unshift(_prev);
				
				//	stop?
				if (_prev.tagName.toLowerCase() == 'h1' || (_prev.getElementsByTagName('h1').length > 0))
				{
					_has_title = true;
					break;
				}
			}
		}
		
		//	still no title?
		//	try to find h1 with most words
		if (_has_title); else
		{
			var 
				_h_text_length = 0,
				_h_found = false,
				_h_found_length = 0
			;
			
			$R.$document.find('h1').each(function (_t_h_i, _t_h_e)
			{
				//	visible
				if (jQuery.expr.filters.hidden(_t_h_e)) { return; }
				
				//	get text length
				_h_text_length = $R.getContent__textFromHTML($(_t_h_e).html()).length;

				//	best?
				if (_h_text_length > _h_found_length)
				{
					_h_found = _t_h_e;
					_h_found_length = _h_text_length;
				}
			});
			
			if (_h_found) {
				//	append to elements
				_elements.unshift(_h_found);
				_has_title = true;
			}
		}
		
		//	still no title?
		//	parse document.title -- if it exists
		if (!_has_title && $R.$document.get(0).title)
		{
			var _parsed_title = $R.$document.get(0).title;
			_parsed_title = _parsed_title.replace
			(
				/^([^\|\->:]+?)\s*([\|\->:])\s*(.*)$/i,
				function (_match, _first, _separator, _second)
				{
					switch (_separator)
					{
						case '-':
							return ((_first.length*1.5) > _second.length ? _first : _second);
							
						case ':':
							return ((_second.length*1.5) > _first.length ? _second : _first);
							
						default:
							return (_first.length > _second.length ? _first : _second);
					}
				}
			).replace(/\^s*/, '').replace(/\s*$/, '');

			var _h_created = $R.$document.get(0).createElement('h1');
				_h_created.innerHTML = _parsed_title;

			//	append to elements
			_elements.unshift(_h_created);
			_has_title = true;
		}
		
		//	get before html
		$R.$document.find('.readable__add_before').each(function (_before_i, _before_e) { _before.unshift(_before_e); });
		for (var i=0,_i=_before.length; i<_i; i++) { _elements.unshift(_before[i]); }

		//	get after html
		$R.$document.find('.readable__add_after').each(function (_after_i, _after_e) { _after.push(_after_e); });
		for (var i=0,_i=_after.length; i<_i; i++) { _elements.push(_after[i]); }
		
		//	display html
		$R.displayHTML($R.processHTML__getHTMLToProcess(_elements));
		return true;
	};
	
	$R.getContent__findHere__getTargetElement = function (_e)
	{
		var 
			_candidates = [],
			_candidates_length = 0,
			_readableCandidateIdsToCandidatesIndex = {}
		;

		$R.$document.find('div')
			.each(function(_i, _e)
			{
				if (_e.childNodes.length == 1); else { return; }
				if (_e.childNodes[0].nodeType == 3); else { return; }
				if ((_e.childNodes[0].nodeValue.length / 65) > 2); else { return; }
				if ($R.getContent__nrWords(_e.childNodes[0].nodeValue) > 35); else { return; }
				
				if ($R.debug) { $R.log('is_paragraph', _e); }
				$(_e).attr('readable_attr_is_paragraph', '1');
			});
		
		//	find all content-containging elements
		$R.$document
			.find('p, br+br, pre, div[readable_attr_is_paragraph], h2, h3')
				.each(function (_i, _e)
				{
					var 
						_parent = $R.getContent__findHere__findPropperParent(_e),
						_id = $.data(_parent, 'readableCandidateId')
					;
					
					switch (true)
					{
						case (_id === -1):
							return;
							
						case (_id == undefined):
						case (_id >= _candidates_length):
							
							_id = ($.expr.filters.hidden(_parent) ? -1 : _candidates_length);
							$.data(_parent, 'readableCandidateId', _id);
		
							if (_id == -1) { return; }
		
							_candidates_length++;
							_candidates.push({
								'element': _parent,
								'paragraphs': 0,
								'readableCandidateId': _id
							});
							break;
					}
					
					_candidates[_id].paragraphs += 1;
				});

		//	if just one, don't waste anymore time
		if (_candidates_length == 1) {
			return (_candidates[0].element);
		}
				
		
		//	add points
		_candidates_length = 0;
		_candidates = $.map(
			_candidates, 
			function (_e, _i)
			{
				_e.computation = $R.getContent__computePointsForElement(_e.element, _e.paragraphs);
				_e.points = _e.computation._points;
				
				//	remove candidate
				switch (true)
				{
					case (_e.computation._theoretical_paragraphs_50_words < 1):
					case (_e.computation._theoretical_paragraphs_50_words < 3 && _e.computation._links_to_text_ratio >= 0.25):
						if ($R.debug) { $R.log('remove candidate', _e, _e.element); }
						return null;
				}

				//	maintain readableCandidateId association
				//	so we can find an element later on
				_readableCandidateIdsToCandidatesIndex['x'+_e.readableCandidateId] = _candidates_length;
				
				_candidates_length++;
				return _e;
			});

		//	subtract points -- double counted
		$.each(
			_candidates, 
			function (_i, _e)
			{
				var 
					_p = _e.element,
					_id = -1
				;
				
				while (true)
				{
					_p = _p.parentNode;
					if (!(_p)) { break; }
					
					_id = $.data(_p, 'readableCandidateId');
					if (_id == undefined || _id == -1) { continue; }

					//	subtract current points from parrent points
					if (_candidates[_readableCandidateIdsToCandidatesIndex['x'+_id]])
					{
						if ($R.debug) { $R.log('subtract points: smaller from bigger', _e.element, _candidates[_readableCandidateIdsToCandidatesIndex['x'+_id]].element); }
						_candidates[_readableCandidateIdsToCandidatesIndex['x'+_id]].points -= _e.points;
					}
				}
			}
		);

		//	remove elements with negative points
		_candidates = $.map(
			_candidates, 
			function (_e, _i) {
				if ($R.debug && (_e.points < 0)) { $R.log('negative points', _e, _e.element); }
				return (_e.points < 0 ? null : _e);
			}
		);

		//	add dom order
		_candidates_length = _candidates.length;
		_candidates = $.map(
			_candidates, 
			function (_e, _i) {
				/* (1) */ //var _dom_points = _e.points * ((_i+1) / _candidates_length);
				/* (2) */ //var _dom_points = _e.points * (_candidates_length / (_candidates_length + _i));
				/* (3) */ //var _dom_points = el.points * (_candidates_length / (_i + 1));
				
				// for (1) & (2) we can then average the result with the real points
				// for (3) an avergae wouldn't make any sense
				
				_e._dom_i = _i;
				_e.points = _e.points * (_candidates_length / (_i + 1));
				
				return _e;
			}
		);

		//	final sort; bigger goes higher
		_candidates.sort(function (a, b) {
			switch (true) {
				case (a.points > b.points): return -1;
				case (a.points < b.points): return 1;
				default: return 0;
			}
		});

		//	no candidates
		if (_candidates_length > 0); else { return false; }
		
		//	debug
		if ($R.debug) {	$R.log('candidates: ', _candidates_length, _candidates); }

		//	check for common parent
		if (_candidates_length > 5)
		{
			var 
				_common_parent = $R.getContent__findHere__findPropperParent(_candidates[0].element)
				_common_nr = 0,
				_total_points = _candidates[0].points
			;
			
			for (var i=1; i<_candidates_length; i++)
			{
				if (_candidates[i].element == _common_parent) { continue; }
				
				if ($R.getContent__findHere__findPropperParent(_candidates[i].element) == _common_parent)
				{
					_total_points += _candidates[i].points;
					_common_nr++;
				}
			}
			
			if (_common_nr > Math.floor(_candidates_length/2) || _common_nr > 4)
			{
				//	create element in same format
				var _common_parent_computation = $R.getContent__computePointsForElement(_common_parent, _common_parent.getElementsByTagName('p').length);
					_common_parent_computation.points = _common_parent_computation._points * _candidates_length;
				
				//	are there enough points?
				if ((0.75 * _common_parent_computation.points) >= _total_points)
				{
					if ($R.debug) { $R.log('common parent', _common_parent); }
					return _common_parent;
				}
			}
		}
		
		//	return
		if ($R.debug) { $R.log(_candidates[0].element); }
		return _candidates[0].element;
	};
	
	
	/* functions */
	/* ========= */

	$R.getContent__computePointsForElement = function(_e, _paragraphsInE)
	{
		var
			//	text
			_text = 								$R.getContent__textFromHTML($(_e).html()),
			_text_length = 							_text.length,
			_words_nr = 							$R.getContent__nrWords(_text),

			//	links
			_links = 								$(_e).find('a'),
			_links_nr = 							_links.length,
			_links_text = 							$R.getContent__textFromHTML($R.getContent__jQueryElementsToHTML(_links)),
			_links_text_length = 					_links_text.length,
			_links_words_nr = 						$R.getContent__nrWords(_links_text),

			//	without links
			_text_length_without_links = 			(_text_length - _links_text_length),
			_words_nr_without_links = 				(_words_nr - _links_words_nr),

			//	theoretical
			_theoretical_lines_of_65_characters = 	(_text_length_without_links / 65),
			_theoretical_paragraphs_3_lines = 		(_theoretical_lines_of_65_characters / 3),
			_theoretical_paragraphs_5_lines = 		(_theoretical_lines_of_65_characters / 5),
			_theoretical_paragraphs_50_words = 		(_words_nr_without_links / 50),
			_theoretical_paragraphs_80_words = 		(_words_nr_without_links / 80),

			//	links ratio
			_links_to_text_ratio = 					(_links_text_length > _text_length_without_links ? 1 : (_links_text_length / _text_length_without_links)),
			_links_words_nr_to_words_nr_ratio =		(_links_words_nr > _words_nr_without_links ? 1 : (_links_words_nr / _words_nr_without_links)),
			
			//	points
			_points = (
				(0
					+ _paragraphsInE
					+ _theoretical_paragraphs_3_lines
					+ _theoretical_paragraphs_5_lines
					+ _theoretical_paragraphs_50_words
					+ _theoretical_paragraphs_80_words
				)
				* (1 - _links_to_text_ratio)
				* (1 - _links_words_nr_to_words_nr_ratio)
			)
		;

		return {
			'_text_length': 						_text_length,
			'_words_nr': 							_words_nr,

			'_links_nr':							_links_nr,
			'_links_text_length':					_links_text_length,
			'_links_words_nr':						_links_words_nr,
			
			'_text_length_without_links':			_text_length_without_links,
			'_words_nr_without_links':				_words_nr_without_links,
			
			'_theoretical_lines_of_65_characters':	_theoretical_lines_of_65_characters,
			'_theoretical_paragraphs_3_lines':		_theoretical_paragraphs_3_lines,
			'_theoretical_paragraphs_5_lines':		_theoretical_paragraphs_5_lines,
			'_theoretical_paragraphs_50_words':		_theoretical_paragraphs_50_words,
			'_theoretical_paragraphs_80_words':		_theoretical_paragraphs_80_words,
			
			'_links_to_text_ratio':					_links_to_text_ratio,
			'_links_words_nr_to_words_nr_ratio':	_links_words_nr_to_words_nr_ratio,
			
			'_points':								_points
		};
	};
	
	$R.getContent__jQueryElementsToHTML = function (_j)
	{
		var _h = '';
		_j.each(function (_i, _e) {	try { _h += $(_e).html(); } catch(e) {} });
		return _h;
	};

	
	$R.getContent__textFromHTML = function (_h)
	{
		//	apparently, .textContent returns value of STYLE and SCRIPT tags

		_t = _h;
		
		//	remove comments
		_t = _t.replace(/<!--[\s\S]*?-->/gi, '');
		
		//	remove whole elements
		_t = _t.replace(/<(button|canvas|embed|frame|input|iframe|link|map|marquee|nobr|noframes|noscript|object|script|select|style|textarea)[\s\S]*?<\/\1>/gi, '');
		_t = _t.replace(/<(button|canvas|embed|frame|input|iframe|link|map|marquee|nobr|noframes|noscript|object|script|select|style|textarea)[\s\S]*?>/gi, '');
		
		//	remove rest of tags
		_t = _t.replace(/<([^>]+?)>/gi, '');
		
		//	remove whitespace
		_t = _t.replace(/\s+/gi, ' ');
		
		return _t;
	};
	
	$R.getContent__nrWords = function (_text)
	{
		var _words_match = _text.match(/\s+/gi);
		return (_words_match != null ? _words_match.length : 1);
	};
	
	$R.getContent__findHere__findPropperParent = function (_e)
	{
		var 
			go = true,
			_p = _e
		;
			
		while(true)
		{
			_p = _p.parentNode;
			
			switch (true)
			{
				case (!(_p)):
					return false;
					
				case (!(_p.nodeType == 1)):
				case (!(_p.tagName.match(/^(article|body|div|dd|li|section|td)$/gi))):
					continue;
			}
			
			break;
		}
		
		return _p;
	};

	
	$R.processHTML__getHTMLToProcess = function (_elements)
	{
		var _h = '';
		
		//	mark ...
		//	stuff to keep
		//	stuff to take out
		
		$.each
		(
			_elements,
			function (_i, _e)
			{
				//	readable__ classes
				$(_e).find('.readable__delete').attr('readable_attr_mark_delete', '1');
				$(_e).find('.readable__keep').attr('readable_attr_mark_keep', '1');
			
			
				//	only content
				$(_e).find('h1 > p, h2 > p, h3 > p, h4 > p, b > p, i > p, e > p, strong > p, em > p').each
					(function (_only_c_i, _only_c_e) {
						$(_only_c_e.parentNode).attr('readable_attr_only_content', '1');
						if ($R.debug) { $R.log('only content', _only_c_e.parentNode); }
					});

				$(_e).find('h1 > br, h2 > br, h3 > br, h4 > br, b > br, i > br, e > br, strong > br, em > br').each
					(function (_only_c_i, _only_c_e) {
						$(_only_c_e.parentNode).attr('readable_attr_only_content', '1');
						if ($R.debug) { $R.log('only content', _only_c_e.parentNode); }
					});

					
				//	big Images
				$(_e).find('img').each
				(
					function (_img_i, _img_e)
					{
						var
							_width = _img_e.width,
							_width = ((_img_e.naturalWidth && _img_e.naturalWidth > _width) ? _img_e.naturalWidth : _width),
							_width = ((_img_e.clientWidth && _img_e.clientWidth > _width) ? _img_e.clientWidth : _width),
							_width = ((_img_e.offsetWidth && _img_e.offsetWidth > _width) ? _img_e.offsetWidth : _width),
						
							_height = _img_e.height,
							_height = ((_img_e.naturalHeight && _img_e.naturalHeight > _height) ? _img_e.naturalHeight : _height),
							_height = ((_img_e.clientHeight && _img_e.clientHeight > _height) ? _img_e.clientHeight : _height),
							_height = ((_img_e.offsetHeight && _img_e.offsetHeight > _height) ? _img_e.offsetHeight : _height)
						;
						
						if ((_width * _height) > 10000)
						{
							$(_img_e).attr('readable_attr_big_image', '1');
							if ($R.debug) { $R.log('big image', _img_e); }
						}
					}
				);
				
				//	images in links
				$(_e).find('a > img').each
				(
					function (_a_img_i, _a_img_e)
					{
						switch (true)
						{
							case ($(_a_img_e).attr('readable_attr_big_image') == '1'):
							case ($R.getContent__nrWords($R.getContent__textFromHTML($(_a_img_e.parentNode).html())) > 10):
								break;
								
							default:
								$(_a_img_e.parentNode).attr('readable_attr_mark_delete', '1');
								if ($R.debug) { $R.log('a > img', _a_img_e.parentNode); }
								break;
						}
					}
				);
				
				//	table/ul/ol/div not enough words
				$(_e).find('ul, ol, table, div').each
				(
					function (_words_i, _words_e)
					{
						//	hidden elements
						if (jQuery.expr.filters.hidden(_words_e))
						{
							$(_words_e).attr('readable_attr_mark_delete', '1');
							if ($R.debug) { $R.log('hidden div/table/ul/ol', _words_e); }
							return;
						}
						
						//	paragraph div
						if ($(_words_e).attr('readable_attr_is_paragraph') == '1') { return; }
						
						
						//	word count
						var 
							_computation = $R.getContent__computePointsForElement(_words_e, 0)
							_big_images = $(_words_e).find('img[readable_attr_big_image]').length,
							_headings = $(_words_e).find('h1, h2, h3, h4, h5, h6').length
						;
						
						switch (true)
						{
							case (_big_images > 0 && _computation._words_nr < 3):
							case (_words_e.tagName.match(/^ul|ol$/i) != null && _computation._links_nr < 6):
								return;
								break;
						
							case (_computation._links_to_text_ratio < 0.5):
								switch (true)
								{
									case (_headings > 0):
									case (_big_images > 1):
									case (_computation._theoretical_paragraphs_80_words > 3):
									case (_computation._words_nr > 15 && _computation._links_to_text_ratio < 0.25):
										return;
										break;
								}
								break;
						}
						
						$(_words_e).attr('readable_attr_mark_delete', '1');
						if ($R.debug) { $R.log('not enough words div/table/ul/ol', _words_e); }
					}
				);
			
				//	keep some elements
				$(_e).find('pre, code, nobr, video').each
				(
					function (_keep_i, _keep_e)
					{
						$(_keep_e).attr('readable_attr_mark_keep', '1');
						if ($R.debug) { $R.log('keep', _keep_e); }
					}
				);
			
				//	keep flash
				$(_e).find('object > param[name=\'movie\']').each
				(
					function (_param_i, _param_e)
					{
						if ($(_param_e).attr('value').match(/(flickr|vimeo|yahoo|youtube)\.com/))
						{
							$(_param_e.parentNode).attr('readable_attr_mark_keep', '1');
							if ($R.debug) { $R.log('keep', _param_e.parentNode); }
						}
					}
				);
				
				$(_e).find('embed[src], iframe[src]').each
				(
					function (_embed_i, _embed_e)
					{
						if ($(_embed_e).attr('src').match(/(flickr|vimeo|yahoo|youtube)\.com/))
						{
							$(_embed_e).attr('readable_attr_mark_keep', '1');
							if ($R.debug) { $R.log('keep', _embed_e); }
						}
					}
				);

				
				//	get element html
				switch (true)
				{
					case (_e.tagName.match(/^h(1|2|3|4|5|6)$/i) != null):
					case (_e.tagName.match(/^p|table|ul|ol$/i) != null):
						_h += ''
							+ '<' + _e.tagName.toLowerCase() + '>'
							+ $(_e).html()
							+ '</' + _e.tagName.toLowerCase() + '>'
						;
						break;
						
					default:
						_h += $(_e).html();
						break;
				}
			}
		);
		
		return _h;
	};

	$R.processHTML__findEndTag = function (_html, _tag, _start_tag_pos)
	{
		//	self closing tags
		switch (_tag)
		{
			case 'img':
			case 'br':
			case 'hr':
			case 'embed':
			
				var _r = />/ig;
					_r.lastIndex = _start_tag_pos;
					_r.exec(_html);
				
				return (_r.lastIndex);
		}

		
		//	count opens and closes
		var
			_r_open = new RegExp('<'+_tag+'[^a-z0-9]', 'ig'),
			_r_close = new RegExp('</'+_tag+'>', 'ig'),
			_r_close_main = new RegExp('</'+_tag+'>', 'ig'),
			_r_match,
			_r_subString
		;
		_r_close_main.lastIndex = _start_tag_pos;
		
		while (true)
		{
			_r_match = _r_close_main.exec(_html);
			if (_r_match); else { return false; }
			
			_r_subString = _html.substring(_start_tag_pos, _r_close_main.lastIndex);
			
			var
				_open_nr = _r_subString.match(_r_open),
				_open_nr = (_open_nr ? _open_nr.length : 0),
				_close_nr = _r_subString.match(_r_close),
				_close_nr = (_close_nr ? _close_nr.length : 0)
			;
			
			if ((_open_nr > 0) && (_open_nr == _close_nr)){
				return (_r_close_main.lastIndex);
			}
		}
	};

	$R.processHTML = function (_h)
	{
		//	remove comments
		_h = _h.replace(/<!--[\s\S]*?-->/gi, '');
		
		//	normalize some stuff
		_h = _h.replace(/<\s+/gi, '$1');
		_h = _h.replace(/\s+>/gi, '$1');
		_h = _h.replace(/\s+\/>/gi, '/>');
		_h = _h.replace(/\s*=\s*/gi, '=');
		_h = _h.replace(/(&nbsp;)+/gi, ' ');
		
		//	hold repository
		var
			_hold_repository = {},								// as object
			_hold_repository_length = 0,						// length
			_readable_attr_regex = /<([a-z0-9]+)([^>]+?)readable_attr_(big_image|mark_keep|mark_delete|only_content)="1"([^>]*)>/ig,
			_readable_attr_regex_match
		;

		while (true)
		{
			_readable_attr_regex_match = _readable_attr_regex.exec(_h);
			if (_readable_attr_regex_match); else { break; }
			
			var 
				_whole = _readable_attr_regex_match[0],
				_operation = _readable_attr_regex_match[3],
				_tag = _readable_attr_regex_match[1],
				_start_tag_pos = (_readable_attr_regex.lastIndex - _whole.length),
				_end_tag_pos = $R.processHTML__findEndTag(_h, _tag, _start_tag_pos)
			;

			if (_end_tag_pos === false) { continue; }
			var _sub_string = _h.substring(_start_tag_pos, _end_tag_pos);
			
			switch (_operation)
			{
				case 'big_image':
					_hold_repository['i'+_hold_repository_length] = '<div class="readableBigImage">' + _sub_string + '</div>';
					_h = '' 
						+ _h.substr(0, _start_tag_pos)
						+ '[=readable_hold('+_hold_repository_length+')]'
						+ _h.substr(_end_tag_pos)
					;
					_hold_repository_length++;
					break;
					
				case 'mark_keep':
					_hold_repository['i'+_hold_repository_length] = _sub_string;
					_h = '' 
						+ _h.substr(0, _start_tag_pos)
						+ '[=readable_hold('+_hold_repository_length+')]'
						+ _h.substr(_end_tag_pos)
					;
					_hold_repository_length++;
					break;
					
				case 'mark_delete':
					_h = '' 
						+ _h.substr(0, _start_tag_pos)
						+ ' '
						+ _h.substr(_end_tag_pos)
					;
					//	add a space, because we always want to be increasing the lastIndex of the RegEx
					break;
					
				case 'only_content':
					_h = '' 
						+ _h.substr(0, _start_tag_pos)
						+ _sub_string.replace(/^<[^>]+>/i, '').replace(/<\/[^>]+>$/i, '')
						+ _h.substr(_end_tag_pos)
					;
					break;
			}

			_readable_attr_regex.lastIndex = (_start_tag_pos + 1);
		}
		
		//	remove all elements that can not possibly have any content we're interested in
		//	ordered alphabetically
		//		$a = explode('|', 'embed|frame|iframe|map|marquee|noframes|noscript|object|script|select|style|textarea');
		//		sort($a); echo implode('|', $a); die();
		_h = _h.replace(/<(button|canvas|embed|frame|input|iframe|link|map|marquee|nobr|noframes|noscript|object|script|select|style|textarea)[\s\S]*?<\/\1>/gi, '');
		_h = _h.replace(/<(button|canvas|embed|frame|input|iframe|link|map|marquee|nobr|noframes|noscript|object|script|select|style|textarea)[\s\S]*?>/gi, '');
		
		//	replace bold/italic
		_h = _h.replace(/<span style="font-weight:\s*bold[^>]*>([^>]+?)<\/span>/gi, '<b>$1</b>');
		_h = _h.replace(/<span style="font-style:\s*italic[^>]*>([^>]+?)<\/span>/gi, '<i>$1</i>');

		//	remove all attributes from all elements
		//	except for a few select element-attribut pairs
		var _attribute_preg = /\s*([a-z0-9_-]+)="[^"]*"/gi;
		_h = _h.replace
		(
			/<([a-z0-9_-]+)( [^>]+)>/gi, 
			function (_m, _k, _a)
			{
				var _tag = _k.toLowerCase();
				switch (true)
				{
					case (_tag == 'a'):
						return ''
							+ '<'+_k
							+ ' target="_blank"'
							+ _a.replace(
								_attribute_preg, 
								function (__m, __a) { return (__a.match(/^(href|id|name|title)$/i) ? __m : ''); }
							)
							+ '>';
						
					case (_tag == 'img'):
						return ''
							+ '<'+_k
							+ _a.replace(
								_attribute_preg, 
								function (__m, __a) { return (__a.match(/^(height|id|src|width|title)$/i) ? __m : ''); }
							)
							+ '/>';
					
					case (_tag == 'td'):
					case (_tag == 'th'):
						return ''
							+ '<'+_k
							+ _a.replace(
								_attribute_preg, 
								function (__m, __a) { return (__a.match(/^(colspan|id|rowspan)$/i) ? __m : ''); }
							)
							+ '>';

					default:
						return ''
							+ '<'+_k
							+ _a.replace(
								_attribute_preg, 
								function (__m, __a) { return (__a.match(/^(id)$/i ) ? __m : ''); }
							)
							+ '>';
				}
			}
		);

		//	make BRs out of empty Ps
		_h = _h.replace(/<p>\s*<\/p>/gi, '<br/><br/>');

		//	delete soft BRs -- whatever the fuck those are
		_h = _h.replace(/<br[^>]*?soft[^>]*>/gi, '');
		
		//	normalize BRs, HRs
		_h = _h.replace(/<(br|hr)[^>]*>/gi, '<$1/>');

		//	remove all self closing elements -- except for br and hr
		_h = _h.replace(/<(?!(br|hr|img))([^>]+)\/>/gi, '');

		//	remove tags of some elements -- but leave content
		//	plus elements with underscore in their definition
		_h = _h.replace(/<\/?(body|center|fieldset|font|form|span)([^>]*)>/gi, '');
		_h = _h.replace(/<\/?([a-z]+)(_|:)([a-z]+)([^>]*)>/gi, '');

		//	make Ps out of bits of text with double BRs splattered throughout
		_h = _h.replace(/<br\/>\s*<br\/>/gi, '</p><p>');

		//	remove <br/> after p
		_h = _h.replace(/<\/(div|h\d|ol|p|table|ul)>\s*<br\/>/gi, '</$1>');
		_h = _h.replace(/<br\/>\s*<(div|h\d|ol|p|table|ul)>/gi, '</$1>');

		//	remove <br/> inside p, div
		_h = _h.replace(/<(p|div)>\s*<br\/>\s*<\/\1>/gi, '');
	
		//	put stuff back
		_h = _h.replace
		(
			/\[=readable_hold\(([0-9]+)\)\]/gi,
			function (_match, _key) {
				return (_hold_repository['i'+_key] ? _hold_repository['i'+_key] : '').replace(/<([^>]+?)style="[^">]+"([^>]*)>/i, '<$1$2>');
			}
		);
	
		return _h;
	};


	$R.displayHTML = function (_h)
	{
		//	display processed
		$R.$iframeText.html($R.processHTML(_h));

		//	fix named anchor links
		//	======================
		$R.$iframeText
			.find('a[href]')
				.each(function (_i, _e)
				{
					var _href = $(_e).attr('href').replace($R.URL, '');
					
					//	only anchors
					if (_href.match(/^#/gi)); else { return; }

					//	only anchor name
					_href = _href.substr(1);
					
					//	set full path to href -- if user copies the link, it will be complete
					$(_e).attr('href', $R.URL + '#' + _href);

					//	bind function
					$(_e).click(function(){ $R.goToNamedAnchor(_href); return false; });
				});
	};
	
	
/* show functions */
/* ============== */

	$R.scrolledWindowWhileReadableVisible = function ()
	{
		if ($R.iOS) { return; }
	
		//	if original window is somehow scrolled, while Readable is visible
		//	move the cover and the iframe
		//	this event is binded and unbinded by the show/hide functions
	
		var _win_top = $($R.win).scrollTop()+'px';

		$R.$iframe.css('top', _win_top);
		$R.$cover.css('top', _win_top);
	};

	$R.show = function ()
	{
		//	before visible
		$R.$document
			.find('body, html')
				.addClass('readableBeforeVisible');
	
		//	frame
		$(window).scrollTop(0);

		var 
			_win_height = $($R.win).height(),
			_win_v_scroll = $($R.win).scrollTop()
		;
		
		//	set cover to above scroll
		$R.$cover.show();
		$R.$cover.css('top', (_win_v_scroll-_win_height)+'px');
		
		//	animate cover down
		$R.$cover.animate
		(
			{top:_win_v_scroll+'px'}, 
			'normal',
			function ()
			{
				//	hide scrollbar and objects
				$R.$document
					.find('body, html')
					.add($R.$iframe)
						.addClass('readableVisible');

				//	set min-height
				$('#body').css('min-height', $R.$iframe.height()+'px');
						
				//	show iframe
				$R.$iframe.css('top', $($R.win).scrollTop()+'px');

				//	hide cover
				$R.$cover.hide();
				
				//	bind to scroll
				$($R.win.document).bind('scroll', $R.scrolledWindowWhileReadableVisible);
				
				//	focus
				if (window.focus) { window.focus(); }
		
				//	finished
				$R.visible = true;
			}
		);
	};
	
	$R.hide = function ()
	{
		var 
			_win_height = $($R.win).height(),
			_win_v_scroll = $($R.win).scrollTop()
		;

		//	unbind
		$($R.win.document).unbind('scroll', $R.scrolledWindowWhileReadableVisible);
		
		//	show cover
		$R.$cover.show();
		
		//	hide
		$R.$iframe.css('top', '-100%');

		//	show scrollbars and objects
		$R.$document
			.find('body, html')
			.add($R.$iframe)
				.removeClass('readableVisible');

		$R.$cover.animate
		(
			{top:_win_v_scroll-_win_height+'px'},
			'normal', 
			function ()
			{
				//	hide
				$R.$cover.css('top', '-100%');
				$R.$cover.hide();

				//	before visible
				$R.$document
					.find('body, html')
						.removeClass('readableBeforeVisible');
				
				//	focus
				if ($R.win.focus) { $R.win.focus(); }
				
				//	finished
				$R.visible = false;
			}
		);
	};

	
/* launch */
/* ====== */

	$R.bookmarkletClicked = function ()
	{
		//	console might not have been activated on first run
		if ($R.debug) { $R.initializeWriteLogFunction(); }

		
		if ($R.visible)
		{
			$R.hide();
		}
		else
		{
			if ($R.debug) { $R.timerStart('bookmarkletClicked'); }

			$R.setOptions();
			$R.getContent();
			
			if ($R.debug) {	$('#menu_debug_time').html(($R.timerEnd()/1000).toPrecision(2)); }
			
			$R.show();
		}
		
		$R.bookmarkletTimer = false;
	};

	//	custom hook
	if ($R.afterLoadCustomHook) { $R.afterLoadCustomHook(); }

	//	auto-launch
	$R.bookmarkletClicked();


/* finish */
/* ====== */
	
		})(window.parent.$readable);
	}
);